import axios, { AxiosInstance, AxiosResponse } from "axios";
import { useAuthStore } from "@/stores/authStore";
import { toast } from "sonner";

/**
 * API响应接口定义
 * @template T 响应数据类型
 */
export interface ApiResponse<T = unknown> {
  code: number;
  msg: string;
  data?: T;
  count?: number;
}

/**
 * HTTP请求客户端
 */
class HttpClient {
  private instance: AxiosInstance;

  constructor() {
    this.instance = axios.create({
      baseURL: "/app/tmadmin",
      headers: {
        "Content-Type": "application/json",
      },
      timeout: 10 * 1000,
    });

    this.setupInterceptors();
  }

  /**
   * 设置请求和响应拦截器
   */
  private setupInterceptors(): void {
    // 请求拦截器
    this.instance.interceptors.request.use(
      (config) => {
        const token = useAuthStore.getState().auth.token?.access_token;
        if (token) {
          config.headers["authorization"] = `Bearer ${token}`;
        }
        return config;
      },
      (error) => {
        return Promise.reject(error);
      }
    );

    // 响应拦截器
    this.instance.interceptors.response.use((response: AxiosResponse) => {
      const { data } = response;

      if (response.status === 200) {
        if (data && data.code === 0) {
          return response;
        } else {
          toast.error(data.msg || "系统错误");
          return Promise.reject(new Error(data.msg || "系统错误"));
        }
      } else {
        toast.error("网络异常");
        return Promise.reject(new Error("网络异常"));
      }
    });
  }

  /**
   * 发送GET请求
   * @param url 请求地址
   * @param params 请求参数
   * @returns Promise
   */
  public get<T = unknown>(
    url: string,
    params?: object
  ): Promise<AxiosResponse<ApiResponse<T>>> {
    return this.instance.get<ApiResponse<T>>(url, { params });
  }

  /**
   * 发送POST请求
   * @param url 请求地址
   * @param data 请求数据
   * @param file 要上传的文件
   * @param onProgress 上传进度回调函数
   * @returns Promise
   */
  public post<T = unknown>(
    url: string,
    data?: object,
    file?: File,
    onProgress?: (percent: number) => void
  ): Promise<AxiosResponse<ApiResponse<T>>> {
    // 如果没有文件，使用普通的 JSON 请求
    if (!file) {
      return this.instance.post<ApiResponse<T>>(url, data);
    }

    // 处理文件上传
    const formData = new FormData();

    // 添加文件到 FormData
    formData.append("file", file);

    // 添加其他数据到 FormData
    if (data && typeof data === "object") {
      Object.entries(data).forEach(([key, value]) => {
        formData.append(key, String(value));
      });
    }

    // 创建取消令牌
    const cancelTokenSource = axios.CancelToken.source();

    // 创建节流函数
    let lastProgressTime = 0;
    const throttleProgress = (percent: number) => {
      const now = Date.now();
      if (now - lastProgressTime > 100 || percent === 100) {
        // 100ms节流，但确保100%进度一定会触发
        lastProgressTime = now;
        onProgress?.(percent);
      }
    };

    // 获取token
    const token = useAuthStore.getState().auth.token?.access_token;

    // 发送请求
    return axios({
      method: "post",
      url: `${this.instance.defaults.baseURL}${url}`,
      data: formData,
      headers: {
        "Content-Type": "multipart/form-data",
        ...(token ? { authorization: `Bearer ${token}` } : {}),
      },
      cancelToken: cancelTokenSource.token,
      onUploadProgress: (progressEvent) => {
        if (progressEvent.total && onProgress) {
          const percent = Math.round(
            (progressEvent.loaded * 100) / progressEvent.total
          );
          throttleProgress(percent);
        }
      },
      timeout: 60000, // 上传文件给予更长的超时时间
    });
  }
}

// 创建HTTP客户端实例
const httpClient = new HttpClient();

/**
 * GET请求
 * @param url 请求地址
 * @param params 请求参数
 * @returns Promise
 */
export const get = <T = unknown>(
  url: string,
  params?: object
): Promise<AxiosResponse<ApiResponse<T>>> => {
  return httpClient.get<T>(url, params);
};

/**
 * POST请求
 * @param url 请求地址
 * @param data 请求数据
 * @param file 要上传的文件
 * @param onProgress 上传进度回调函数
 * @returns Promise
 */
export const post = <T = unknown>(
  url: string,
  data?: object,
  file?: File,
  onProgress?: (percent: number) => void
): Promise<AxiosResponse<ApiResponse<T>>> => {
  return httpClient.post<T>(url, data, file, onProgress);
};
